
KMG.MonitorBackgroundShader = {

	vertexShader: [
		"varying vec2 textureVarying;",

		"void main() {",
		"gl_Position = projectionMatrix * modelViewMatrix *vec4(position.xyz, 1.0);",
		"textureVarying = uv;",
		"}",

	].join( "\n" ),

	fragmentShader: [

		"uniform sampler2D texture;",
		"varying vec2 textureVarying;",

		"void main() {",
		"gl_FragColor = texture2D( texture, textureVarying );",
		"}",

	].join( "\n" )

};

KMG.MonitorBackgroundObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var planeMapImage =  this.planeMapImage = new THREE.Object3D();

	var imagePath = "./img/monitor-bkg.jpg";
	var runnerTexture = new THREE.ImageUtils.loadTexture( imagePath );

	var uniforms = {
		texture: { type: "t", value: runnerTexture },
	};

	var shaderMaterial = new THREE.ShaderMaterial( {
		uniforms: 		uniforms,
		vertexShader:   KMG.MonitorBackgroundShader.vertexShader,
		fragmentShader: KMG.MonitorBackgroundShader.fragmentShader,
		blending: 		THREE.NormalBlending,
		depthTest: 		false,
		depthWrite: 	false,
		transparent:	true,
		sizeAttenuation: false,
	});
	var geometry = new THREE.PlaneGeometry(1920, 1080);
	var mesh = new THREE.Mesh(geometry, shaderMaterial);
	planeMapImage.add(mesh);

	planeMapImage.update = function() {
	};

	return planeMapImage;

};
KMG.MonitorBackgroundObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.MonitorStationObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.lineMaterials = [];

	function textures (lineName, size, angle) {

		var canvas = document.createElement( 'canvas' );
		var ctx = canvas.getContext( '2d' );

		canvas.width = size;
		canvas.height = size;

		ctx.fillStyle = '#000000';
		ctx.globalAlpha = 1.0;
		ctx.fillRect(0, 0, size, size);
		ctx.fillStyle = '#fff';
		ctx.strokeStyle = '#fff';
		ctx.font = "10px sans-serif";
		ctx.textBaseline = 'hanging';
		ctx.translate(size/2.0, size/2.0);
		ctx.rotate(angle*Math.PI/180.0);
		//ctx.textAlign = 'left';
		ctx.fillText(lineName , 0, 5);

		var canvasTexture = new THREE.Texture(canvas);
		canvasTexture.wrapS = THREE.ClampToEdgeWrapping;
		canvasTexture.wrapT = THREE.ClampToEdgeWrapping;
		canvasTexture.minFilter = THREE.NearestFilter;
		canvasTexture.minFilter = THREE.NearestFilter;
		canvasTexture.needsUpdate = true;

		return canvasTexture;
	}

	function CreatePoint(texture, size, color)
	{
		var particlesGeo =  new THREE.Geometry();
		particlesGeo.dynamic = true;

		var shaderMaterial = new THREE.ParticleSystemMaterial( {
			size: size,
			color: color,
			map: texture,
			blending: 		THREE.AdditiveBlending,
			depthTest: 	false,
			depthWrite: 	false,
			transparent:	true,
			sizeAttenuation: false,
		});

		particlesGeo.vertices.push( new THREE.Vector3(0, 0, 0.0) );

		var pSystem = new THREE.ParticleSystem( particlesGeo, shaderMaterial );
		pSystem.dynamic = true;
		pSystem.rotation.x += Math.PI/2;
		return pSystem;
	}

	this.addGeometry = function(start, end, text, angle)
	{
		var points = [];
		points.push(start);
		points.push(end);

		var times = [];
		var pointSize = points.length;
		var sumTime = 1000;
		var detaTile = sumTime / pointSize;
		for (var i = 0; i < pointSize; i++) {
			times.push(i*detaTile);
		}

		var geometry = new THREE.Geometry();
		for( var i = 0; i < points.length; i ++ ) {
			geometry.vertices.push( points[i] );
		}
		geometry.size = points.size;

		var meshLine = new StreamMeshLine();
		meshLine.setGeometry( geometry, times );

		var resolution = new THREE.Vector2( 1920, 1080);
		var lineMaterial = new THREE.StreamMeshLineMaterial( {
			vertexShader: THREE.CycleStreamMeshLineShader.vertexShader,
			fragmentShader: THREE.CycleStreamMeshLineShader.fragmentShader,
			useMap: false,
			useAlphaMap: false,
			color: new THREE.Color( 0xffffff ),
			opacity: 1,
			transparent: true,
			resolution: resolution,
			sizeAttenuation: false,
			lineWidth: 8,
			near: config.camera.near,
			far: config.camera.far,
			invertType: 1,
			sycleType: 1,
			sumTime: sumTime,
			sycleTime: sumTime / 10,
			traceTime: sumTime / 10,
			currentTime: 0.0,
			depthTest: true,
			depthWrite: true,
			blending: THREE.AdditiveBlending,
		});
		this.lineMaterials.push(lineMaterial);

		var mesh = new THREE.Mesh( meshLine.geometry, lineMaterial );
		this.add(mesh);


		var x = start.x + 7 * (end.x - start.x) / 8;
		var y = start.y + 7 * (end.y - start.y) / 8;
		var textObj = CreatePoint(textures(text, 64.0, angle), 64.0, 0x00ff00);
		textObj.position = new THREE.Vector3(x, y, 0);
		this.context.mainScene.add( textObj );
	};

	this.currentTime = 0;
	this.update = function()
	{
		this.currentTime -= 2.0;

		var near = this.context.mainCamera.near;
		var far = this.context.mainCamera.far;
		for (var i = 0; i < this.lineMaterials.length; i++) {
			var lineMaterial = this.lineMaterials[i];
			lineMaterial.near = near;
			lineMaterial.far = far;
			var invertType = lineMaterial.uniforms.invertType;
			var currentTime = lineMaterial.uniforms.currentTime;
			if (currentTime != null) {
				currentTime.value = this.currentTime;
			}
		}
	};

	this.addBeiJingStation = function()
	{
		var height = 400;
		var offset = 80;
		var angle = 15;
		var startPos = new THREE.Vector3(1220-960, (1080-700)-540, 0);

		this.addGeometry( startPos, new THREE.Vector3(startPos.x - 3*offset, startPos.y + height, 0), "M13", 90-3*angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x - 2*offset, startPos.y + height, 0), "M15", 90-2*angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x - offset, startPos.y + height, 0), "M7", 90-angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x, startPos.y + height, 0), "M2", 90 );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x + offset, startPos.y + height, 0), "M4", 90+angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x + 2*offset, startPos.y + height, 0), "M12", 90+2*angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x + 3*offset, startPos.y + height, 0), "M9", 90+3*angle );
	};
	this.addSanYaStation = function()
	{
		var height = 250;
		var offset = 80;
		var angle = 15;
		var startPos = new THREE.Vector3(1143-960, (1080-1022)-540, 0);

		this.addGeometry( startPos, new THREE.Vector3(startPos.x - offset, startPos.y + height, 0), "M1", 90-angle );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x, startPos.y + height, 0), "M3", 90 );
		this.addGeometry( startPos, new THREE.Vector3(startPos.x + offset, startPos.y + height, 0), "M8", 90+angle );
	};
	this.addBeiJingStation();
	this.addSanYaStation();

};
KMG.MonitorStationObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.MonitorEffectsComposer = function(context, renderer) {

	var renderTargetParameters = {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.LinearFilter,
		format: THREE.RGBAFormat,
		stencilBuffer: false
	};

	THREE.EffectComposer.call( this, renderer );
	var scope = this;
	this.context = context;
	this.renderer = renderer;

	var baseRenderPass = new THREE.RenderPass( context.baseScene, context.baseCamera );
	baseRenderPass.clear = true;
	this.addPass( baseRenderPass );

	var mainRenderPass = new THREE.RenderPass( context.mainScene, context.mainCamera );
	mainRenderPass.clear = false;
	this.addPass( mainRenderPass );

	var effectMainRenderPass = new THREE.RenderPass( context.effectScene, context.mainCamera );
	effectMainRenderPass.clear = false;
	this.addPass( effectMainRenderPass );

	var effectMainFXAA = new THREE.ShaderPass( THREE.FXAAShader );
	//this.addPass( effectMainFXAA );

	var effectMainHBlur = new THREE.ShaderPass( THREE.HorizontalBlurShader );
	//this.addPass( effectMainHBlur );
	var effectMainVBlur = new THREE.ShaderPass( THREE.VerticalBlurShader );
	//this.addPass( effectMainVBlur );

	var effectMainBloom = new THREE.BloomPass( 0.0 );
	//this.addPass( effectMainBloom );

	var effectSave = new THREE.SavePass( new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters ) );
	effectSave.clear = false;
	this.addPass( effectSave );

	var clearDepthPass = new THREE.ClearDepthPass( );
	clearDepthPass.clear = false;
	this.addPass( clearDepthPass );

	var effectRenderPass = new THREE.RenderPass( context.effectScene, context.mainCamera );
	effectRenderPass.clear = true;
	effectRenderPass.clearAlpha = 0;
	effectRenderPass.clearColor = 0x000000;
	this.addPass( effectRenderPass );

	var depthPass = new THREE.DepthPass( );
	depthPass.clear = false;
	this.addPass( depthPass );

	var effectFXAA = new THREE.ShaderPass( THREE.FXAAShader );
	this.addPass( effectFXAA );

	var effectHBlur = new THREE.ShaderPass( THREE.HorizontalBlurShader );
	this.addPass( effectHBlur );
	var effectVBlur = new THREE.ShaderPass( THREE.VerticalBlurShader );
	this.addPass( effectVBlur );

	var effectBloom = new THREE.BloomPass( 0.0 );
	this.addPass( effectBloom );

	var effectBlend = new THREE.ShaderPass( THREE.MixTextureShader, "tDiffuse1" );
	effectBlend.uniforms[ 'opacity' ].value = 1.0;
	effectBlend.uniforms[ 'tDiffuse2' ].value = effectSave.renderTarget;
	effectBlend.renderToScreen = true;
	this.addPass( effectBlend );

	//var effectCopy = new THREE.ShaderPass( THREE.CopyShader );
	//effectCopy.renderToScreen = true;
	//this.addPass( effectCopy );

	this.effect = 1;
	this.opacity = 0;
	this.sender = null;
	this.callback = null;
	this.enterEffect = function(callback, sender) {
		this.effect = 1;
		this.opacity = 0;
		this.sender = sender;
		this.callback = callback;
	};
	this.exitEffect = function(callback, sender) {
		this.effect = 0;
		this.opacity = 1;
		this.sender = sender;
		this.callback = callback;
	};

	this.update = function() {
		if (this.effect == 0) {
			this.opacity -= 0.05;
			if (this.opacity < 0) {
				this.opacity = 0;
				if (this.callback != null) {
					this.callback(this.sender);
					this.sender = null;
					this.callback = null;
				}
			}
		} else {
			this.opacity += 0.05;
			if (this.opacity > 1) {
				this.opacity = 1;
				if (this.callback != null) {
					this.callback(this.sender);
					this.sender = null;
					this.callback = null;
				}
			}
		}

		var mainBlurAmount = 0.0;
		effectMainHBlur.uniforms[ 'h' ].value = mainBlurAmount / ( window.innerWidth / 2 );
		effectMainVBlur.uniforms[ 'v' ].value = mainBlurAmount / ( window.innerHeight / 2 );
		effectMainFXAA.uniforms["resolution"].value.x = 1 / window.innerWidth;
		effectMainFXAA.uniforms["resolution"].value.y = 1 / window.innerHeight;
		effectMainBloom.copyUniforms["opacity"].value = 0.0;

		var effectBlurAmount = 1.0;
		effectHBlur.uniforms[ 'h' ].value = effectBlurAmount / ( window.innerWidth / 2 );
		effectVBlur.uniforms[ 'v' ].value = effectBlurAmount / ( window.innerHeight / 2 );
		effectFXAA.uniforms["resolution"].value.x = 1 / window.innerWidth;
		effectFXAA.uniforms["resolution"].value.y = 1 / window.innerHeight;
		effectBloom.copyUniforms["opacity"].value = 5.0;

		effectBlend.uniforms[ 'opacity' ].value = this.opacity;
		effectBlend.uniforms[ 'tDiffuse2' ].value = effectSave.renderTarget;
	};

};
KMG.MonitorEffectsComposer.prototype = Object.create( THREE.EffectComposer.prototype );


KMG.MonitorScene = function ( domElement, config ) {

	var scope = this;
	this.config = config;
	this.domElement = ( domElement !== undefined ) ? domElement : document;
	this.visible = true;

	this.context = {
		container : null,
		composer : null,
		renderer : null,
		baseCamera : null,
		baseScene : null,
		mainCamera : null,
		mainScene : null,
		effectScene : null,
		containerWidth : 0,
		containerHeight : 0,
		objects : [],
	};

	this.enterScene = function(callback, sender)
	{
		scope.context.composer.enterEffect(callback, sender);
	};

	this.exitScene = function(callback, sender)
	{
		scope.context.composer.exitEffect(callback, sender);
	};

	this.isVisible = function()
	{
		return this.visible;
	};

	this.setVisible = function(visible)
	{
		this.visible = visible;
		this.context.controls.enabled = visible;
	};

	this.addObjectToBaseScene = function(object)
	{
		this.context.objects.push(object);
		this.context.baseScene.add(object);
	};

	this.addObjectToMainScene = function(object)
	{
		this.context.objects.push(object);
		this.context.mainScene.add(object);
	};

	this.addObjectToEffectScene = function(object)
	{
		this.context.objects.push(object);
		this.context.effectScene.add(object);
	};

	this.reset = function()
	{

	};

	this.start = function()
	{

	};

	this.stop = function()
	{

	};

	this.onSize = function()
	{
		this.context.containerWidth = window.innerWidth;
		this.context.containerHeight = window.innerHeight;

		this.context.baseCamera.aspect = window.innerWidth / window.innerHeight;
		this.context.baseCamera.updateProjectionMatrix();
		this.context.mainCamera.aspect = window.innerWidth / window.innerHeight;
		this.context.mainCamera.updateProjectionMatrix();

		this.context.renderer.setSize( window.innerWidth, window.innerHeight );
		this.context.composer.setSize(window.innerWidth, window.innerHeight);
	};

	this.onRender = function()
	{
		if (!this.visible) {
			return;
		}

		scope.context.containerWidth = window.innerWidth;
		scope.context.containerHeight = window.innerHeight;
		scope.context.controls.update();

		for (var i = 0; i < scope.context.objects.length; i++) {
			scope.context.objects[i].update();
		}

		scope.context.renderer.setClearColor( 0x001862, 1.0 );
		scope.context.renderer.clear(true, true, true);

		//scope.context.renderer.render(this.context.effectScene, this.context.mainCamera);
		scope.context.composer.render(0.1);
	};

	this.context.container = this.domElement;
	this.context.renderer = this.config.renderer;

	var cameraZ = 1300;
	this.context.baseCamera = new THREE.PerspectiveCamera( this.config.camera.fieldOfView, window.innerWidth / window.innerHeight, this.config.camera.near, this.config.camera.far );
	this.context.baseCamera.position.z = cameraZ;
	var baseScene = new THREE.Scene();
	var baseAmbientLight = new THREE.AmbientLight( 0x888888 );
	baseScene.add( baseAmbientLight );
	var baseDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	baseDirectional.position.set( -1000000, -1000000, 1000000 );
	baseScene.add( baseDirectional );
	baseScene.updateMatrix();
	scope.context.baseScene = baseScene;
	//this.addObjectToBaseScene(new KMG.BackgroundPlaneObject(this.context, this.config));

	this.context.mainCamera = new THREE.PerspectiveCamera( this.config.camera.fieldOfView, window.innerWidth / window.innerHeight, this.config.camera.near, this.config.camera.far );
	this.context.mainCamera.position.z = cameraZ;
	var mainScene = new THREE.Scene();
	var mainAmbientLight = new THREE.AmbientLight( 0x888888 );
	mainScene.add( mainAmbientLight );
	var mainDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	mainDirectional.position.set( -1000000, -1000000, 1000000 );
	mainScene.add( mainDirectional );
	mainScene.updateMatrix();
	scope.context.mainScene = mainScene;

	var effectScene = new THREE.Scene();
	var effectAmbientLight = new THREE.AmbientLight( 0x888888 );
	effectScene.add( effectAmbientLight );
	var effectDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	effectDirectional.position.set( -1000000, -1000000, 1000000 );
	effectScene.add( effectDirectional );
	effectScene.updateMatrix();
	this.context.effectScene = effectScene;

	this.addObjectToMainScene(new KMG.MonitorBackgroundObject(this.context, this.config));
	this.addObjectToEffectScene(new KMG.MonitorStationObject(this.context, this.config));

	this.context.composer = new KMG.MonitorEffectsComposer(this.context, this.context.renderer);
	this.context.objects.push(this.context.composer);

    this.context.controls = new THREE.OrbitControls(this.context.mainCamera,this.context.renderer.domElement );
    this.context.controls.update(true);
};